package com.howard.dao.impl;

import java.lang.reflect.InvocationTargetException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.SqlProvider;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;

import com.howard.core.AbstractBasicCoreDao;
import com.howard.dao.UserDao;
import com.howard.entity.User;

/**
 * User Dao Implements
 *
 * @author <a href="mailto:howard.he0329@gmail.com">Howard.He</a>
 * @version 1.0
 *
 */
@Repository
public class UserDaoImpl extends AbstractBasicCoreDao implements UserDao {

	protected final Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * create SimpleJdbcInsert
	 *
	 * @return SimpleJdbcInsert
	 */
	private SimpleJdbcInsert createSimpleJdbcInsert() {
		SimpleJdbcInsert insert = new SimpleJdbcInsert(getJdbcTemplate())
				.withTableName("c_user")
				.usingColumns("name", "accountName", "mail", "password",
						"mobile", "phone", "sex", "status", "createDate",
						"remark").usingGeneratedKeyColumns("id");
		return insert;
	}

	@SuppressWarnings("unchecked")
	@Override
	public long insertUser(User user) throws DataAccessException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		SimpleJdbcInsert insert = createSimpleJdbcInsert();
		Map<String, Object> userMap = null;
		userMap = PropertyUtils.describe(user);
		logger.info("userMap: " + userMap);
		return insert.executeAndReturnKey(userMap).longValue();
	}

	@Override
	public int[] insertBatchUsers(final List<User> users)
			throws DataAccessException {
		long start = System.currentTimeMillis();
		SimpleJdbcInsert batchInsert = createSimpleJdbcInsert();
		List<SqlParameterSource> sources = new ArrayList<SqlParameterSource>();
		for (User user : users) {
			sources.add(new BeanPropertySqlParameterSource(user));
		}
		int[] returnKey = batchInsert
				.executeBatch((SqlParameterSource[]) sources
						.toArray(new BeanPropertySqlParameterSource[sources
								.size()]));
		long end = System.currentTimeMillis();
		logger.info("run time: " + (end - start) + " s");
		return returnKey;
	}

	@Override
	public int[] insertBatchUsers(User[] users) throws DataAccessException {
		return insertBatchUsers(Arrays.asList(users));
	}

	@Override
	public User updateUser(final User user) {
		class UpdateUserPreparedStatementCallback implements
				PreparedStatementCallback<User>, SqlProvider {
			@Override
			public String getSql() {
				StringBuilder sb = new StringBuilder();
				sb.append("update c_user u set ");
				if (StringUtils.isNotBlank(user.getName()))
					sb.append("u.name = " + user.getName());
				return null;
			}

			@Override
			public User doInPreparedStatement(PreparedStatement ps)
					throws SQLException, DataAccessException {
				return null;
			}
		}
		final UpdateUserPreparedStatementCallback call = new UpdateUserPreparedStatementCallback();
		jdbcTemplate.execute(call.getSql(), call);
		return user;
	}

	@Override
	public void deleteUser(long id) {
		final StringBuilder delSql = new StringBuilder();
		delSql.append("delete from c_user");
		if (id > 0) {
			delSql.append(" where id = ?");
		}
		jdbcTemplate.update(delSql.toString(), new Object[] {id});
	}

	@Override
	public void deleteAllUsers() throws DataAccessException {
		deleteUser(-1);
	}

	@Override
	public void deleteUser(User user) throws DataAccessException {
		// TODO Auto-generated method stub
	}

	@Override
	public List<User> queryUserForList(String status) throws DataAccessException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public User queryUserById(final long id) throws DataAccessException {
		long start = System.currentTimeMillis();
		User user = getJdbcTemplate().queryForObject(
				"select * from c_user u where u.id = ?", new Object[] { id },
				new BeanPropertyRowMapper<User>(User.class));
		long end = System.currentTimeMillis();
		logger.info("run time: " + (end - start) + "ms");
		return user;
	}

	@Override
	public List<User> queryUserForList() throws DataAccessException {
		long start = System.currentTimeMillis();
		List<User> users = getJdbcTemplate().query("select * from c_user",
				new BeanPropertyRowMapper<User>(User.class));
		long end = System.currentTimeMillis();
		logger.info("run time: " + (end - start) + "ms");
		return users;
	}

	@Override
	public User queryUserByName(final String accountName)
			throws DataAccessException {
		String sql = "select * from c_user u where u.accountName = ?";
		return jdbcTemplate.queryForObject(sql, new Object[] { accountName },
				new BeanPropertyRowMapper<User>(User.class));
	}
}
